
package structure;

import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Iterator;

/**
 * Classe definissante le comportement et la structure d'un DataCenter.
 * 
 * @author David Bernard
 * @since java 1.6
 * 
 * @see DataCenter
 */
public abstract class AbstractDataCenter implements DataCenter,
		Iterable<DataNode>
{
	private static final Object EMPTY = "";
	private final DataNode referenceNode;

	private int nbGet = 0;
	private int nbSet = 0;

	/**
	 * Instancie un nouveau AbstractDataCenter
	 */
	public AbstractDataCenter()
	{
		this.referenceNode = new DataNode();
	}

	@Override
	public Object get(int ligne, int col)
	{
		DataNode node;
		Object out = null;

		this.nbGet++;
		this.referenceNode.setAddress(ligne, col);
		this.referenceNode.setContenu(null);

		node = this.getElement(this.referenceNode);

		if (node != null)
		{
			out = node.getContenu();
		}
		else
		{
			out = AbstractDataCenter.EMPTY;
		}

		return out;
	}

	@Override
	public void set(int ligne, int col, Object newVal)
	{
		String msg = "#set#";
		this.nbSet++;
		this.referenceNode.setAddress(ligne, col);
		this.referenceNode.setContenu(newVal);

		msg += " added";
		this.setElement(this.referenceNode);

		msg += ", nbElem = " + this.size();
		msg += ", content = " + this.referenceNode.toString();
		//System.out.println(msg);
	}

	/**
	 * Getter du nombre de set.
	 * 
	 * @return int, le nombre de set.
	 */
	public int getNbSet()
	{
		return this.nbSet;
	}

	/**
	 * Getter du nombre de get.
	 * 
	 * @return int, le nombre de get.
	 */
	public int getNbGet()
	{
		return this.nbGet;
	}

	@Override
	public void Enregistrer(String nomFichier)
	{
		Iterator<DataNode> iterator = null;
		FileOutputStream fos = null;
		ObjectOutputStream oos = null;
		DataNode node = null;
		File file = new File(nomFichier);
		File tempFile = new File(".temp");

		// System.out.println("#Enregistrer# début");

		try
		{
			try
			{
				fos = new FileOutputStream(tempFile);
				oos = new ObjectOutputStream(fos);

				iterator = this.iterator();

				while (iterator.hasNext())
				{
					node = iterator.next();
					oos.writeObject(node);

					// System.out.println("#écriture# " + node);
				}
			}
			finally
			{
				if (oos != null)
				{
					oos.flush();
					oos.close();
					oos = null;
				}
			}

			tempFile.renameTo(file);
		}
		catch (IOException e)
		{
		}

		// System.out.println("#Enregistrer# fin");
	}

	@Override
	public void Ouvrir(String nomFichier)
	{
		FileInputStream fis = null;
		ObjectInputStream ois = null;
		DataNode node = null;

		// System.out.println("#ouvrir# début");

		try
		{
			try
			{
				fis = new FileInputStream(nomFichier);
				ois = new ObjectInputStream(fis);

				this.removeAllData();

				while (true)
				{
					node = (DataNode) ois.readObject();
					this.setElement(node);
					// System.out.println("#lecture# " + node.toString());
				}
			}
			catch (EOFException e)
			{
				// System.out.println("#EOF#");
			}
			finally
			{
				if (ois != null)
				{
					ois.close();
					ois = null;
				}
			}
		}
		catch (IOException e)
		{
		}
		catch (ClassNotFoundException e)
		{
		}

		// System.out.println("#ouvrir# fin");
	}

	@Override
	public String toString()
	{
		String out = "nbElement = " + this.size();
		out += " nbSet = " + this.nbSet;
		out += " nbGet = " + this.nbGet;
		return out;
	}

	/**
	 * Donne le nombre d'éléments dans le DataCenter
	 * 
	 * @return int, le nombre d'élément dans le tableau.
	 */
	public abstract int size();

	protected abstract void setElement(DataNode node);

	protected abstract DataNode getElement(DataKey cle);

	protected abstract void removeElement(DataKey cle);
}
